package com.gzhryc.servlet;

import java.io.OutputStreamWriter;
import java.util.Enumeration;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gzhryc.common.logging.Logger;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;

import com.gzhryc.servlet.velocity.VelocityTools;

public class VelocityService {

	static Logger log  = Logger.getLogger(VelocityService.class);
	
	static VelocityService me;
	
	public static VelocityService self() {
		return me;
	}
	
	public static VelocityService initial(String templatePath) {
		me = new VelocityService(templatePath);
		return me;
	}

	private VelocityEngine engine;
	private ConcurrentHashMap<String, Class<? extends AbsVelocityTools>> tools;

	public VelocityService(String path) {
		Properties p = new Properties();
		p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
		p.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
		p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, path);
		engine = new VelocityEngine();
		engine.init(p);
		
		tools = new ConcurrentHashMap<String, Class<? extends AbsVelocityTools>>();
		tools.put(VelocityTools.Alias, VelocityTools.class);
	}

	public <T extends AbsVelocityTools> VelocityService addTool(String key, Class<? extends AbsVelocityTools> clazz) {
		tools.put(key, clazz);
		return this;
	}

	public void export(HttpServletRequest request, HttpServletResponse response, String templateName,
			VelocityContext velocityContext) throws Exception {
		setVelocityContext(request, velocityContext);
		// 获取模版
		Template template = engine.getTemplate(templateName, "UTF-8");
		OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
		template.merge(velocityContext, writer);
		writer.flush();
	}

	public void evaluate(HttpServletRequest request, HttpServletResponse response, String templateContent,
			VelocityContext velocityContext) throws Exception {
		setVelocityContext(request, velocityContext);
		OutputStreamWriter writer = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
		engine.evaluate(velocityContext, writer, "StringTemplate", templateContent);
		writer.flush();
	}

	private void setVelocityContext(HttpServletRequest request, VelocityContext velocityContext) {
		boolean hasWebRoot = true;
		Enumeration<String> parameterEnumeration = request.getParameterNames();
		while (parameterEnumeration.hasMoreElements()) {
			String name = parameterEnumeration.nextElement();
			String[] values = request.getParameterValues(name);
			if (values.length == 1) {
				velocityContext.put(name, values[0]);
			} else {
				velocityContext.put(name, values);
			}
			if("webRoot".equals(name)) {hasWebRoot=false;}
		}
		Enumeration<String> attributeEnumeration = request.getAttributeNames();
		while (attributeEnumeration.hasMoreElements()) {
			String name = attributeEnumeration.nextElement();
			velocityContext.put(name, request.getAttribute(name));
			if("webRoot".equals(name)) {hasWebRoot=false;}
		}
		if(hasWebRoot) {
			velocityContext.put("webRoot", request.getServletContext().getContextPath());
		}
		String uri = StringUtils.removeStart(request.getRequestURI(), request.getContextPath());
		velocityContext.put("uri", uri);

		Enumeration<String> keys = tools.keys();
		while (keys.hasMoreElements()) {
			String key = keys.nextElement();
			Class<? extends AbsVelocityTools> clazz = tools.get(key);
			try {
				AbsVelocityTools tool = clazz.newInstance();
				tool.setRequest(request);
				velocityContext.put(tool.getAlias(), tool);
			} catch (InstantiationException e) {
				log.error(e.getMessage(),e);
			} catch (IllegalAccessException e) {
				log.error(e.getMessage(),e);
			}
		}
	}

	public boolean resourceExists(String templateName) {
		return engine.resourceExists(templateName);
	}

}
